<?php
/**
 * Created by WXCH
 * Date: 2020/1/8 0008 19:09
 */

namespace app\api\service;

use app\api\model\User;
use app\lib\enum\ScopeEnum;
use app\lib\exception\TokenException;
use app\lib\exception\WeChatException;
use Exception;

/**
 * 微信登录
 * Class UserToken
 * @package app\api\service
 */
class UserToken extends Token{

    protected $code;
    protected $wxLoginUrl;
    protected $wxAppID;
    protected $wxAppSecret;

    function __construct($code)
    {
        $this->code = $code;
        $this->wxAppID = config('dou.app_id');
        $this->wxAppSecret = config('dou.app_secret');
        $this->wxLoginUrl = sprintf(config('dou.login_url'), $this->wxAppID, $this->wxAppSecret, $this->code);
    }

    public function get(){
        $result = curl_get($this->wxLoginUrl);
        $wxResult = json_decode($result, true);
        if (empty($wxResult)) {
            throw new Exception('获取session_key及openID时异常，微信内部错误');
        } else {
            $loginFail = array_key_exists('errcode', $wxResult);
            if ($loginFail) {
                $this->processLoginError($wxResult);
            } else {
                return $this->grantToken($wxResult);
            }
        }
    }

    // 判断是否重复获取
    private function duplicateFetch(){
        //TODO
    }

    /**
     * 处理微信登陆异常
     * @param $wxResult
     */
    private function processLoginError($wxResult){
        throw new WeChatException(
            [
                'msg' => $wxResult['errmsg'],
                'errorCode' => $wxResult['errcode']
            ]);
    }

    // 写入缓存
    private function saveToCache($wxResult){
        $key = self::generateToken();
        $value = json_encode($wxResult);
        $expire_in = config('setting.token_expire_in');
        $result = cache($key, $value, $expire_in);

        if (!$result){
            throw new TokenException([
                'msg' => '服务器缓存异常',
                'errorCode' => 10005
            ]);
        }
        return $key;
    }

    // 颁发令牌
    private function grantToken($wxResult){
        $openid = $wxResult['openid'];
        $user = User::getByOpenID($openid);
        if (!$user){
            $uid = $this->newUser($openid);
        }else {
            $uid = $user->id;
        }
        $cachedValue = $this->prepareCachedValue($wxResult, $uid);
        $token = $this->saveToCache($cachedValue);
        return $token;
    }

    private function prepareCachedValue($wxResult, $uid){
        $cachedValue = $wxResult;
        $cachedValue['uid'] = $uid;
        $cachedValue['scope'] = ScopeEnum::User;
        return $cachedValue;
    }

    /**
     * 创建新用户
     * @param $openid
     * @return mixed
     */
    private function newUser($openid){
        $user = User::create(
            [
                'openid' => $openid
            ]);
        return $user->id;
    }

}